use crate::algorithms::fo_logic::fol_tree::FolTreeNode;
use crate::algorithms::fo_logic::parser::{parse_and_minimize_fol_formula, parse_fol_formula};
use crate::algorithms::fo_logic::utils::*;
use crate::sketchbook::model::ModelState;
use biodivine_lib_param_bn::symbolic_async_graph::SymbolicContext;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct FirstOrderFormula {
#[serde(
serialize_with = "serialize_tree",
deserialize_with = "deserialize_tree"
)]
tree: FolTreeNode,
}
fn serialize_tree<S>(tree: &FolTreeNode, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&tree.to_string())
}
fn deserialize_tree<'de, D>(deserializer: D) -> Result<FolTreeNode, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
parse_fol_formula(&s).map_err(de::Error::custom)
}
impl fmt::Display for FirstOrderFormula {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.tree)
}
}
impl FirstOrderFormula {
pub fn try_from_str(formula: &str) -> Result<FirstOrderFormula, String> {
Ok(FirstOrderFormula {
tree: parse_fol_formula(formula)?,
})
}
}
impl FirstOrderFormula {
pub fn change_formula(&mut self, new_formula: &str) -> Result<(), String> {
self.tree = parse_fol_formula(new_formula)?;
Ok(())
}
}
impl FirstOrderFormula {
pub fn as_str(&self) -> &str {
&self.tree.formula_str
}
pub fn tree(&self) -> &FolTreeNode {
&self.tree
}
}
impl FirstOrderFormula {
pub fn check_pure_syntax(formula: &str) -> Result<(), String> {
parse_and_minimize_fol_formula(formula, "PLACEHOLDER").map(|_| ())
}
pub fn check_syntax_with_model(formula: &str, model: &ModelState) -> Result<(), String> {
let bn = model.to_bn();
let ctx = SymbolicContext::new(&bn)?;
let tree = parse_and_minimize_fol_formula(formula, "PLACEHOLDER")?;
let function_symbols = collect_unique_fn_symbols(&tree)?;
for (fn_name, arity) in function_symbols.iter() {
if let Ok(var) = get_var_from_implicit(fn_name) {
if !check_update_fn_support(&bn, &var, *arity) {
return Err(format!(
"Variable for update function `{fn_name}` does not exist, or its arity is different."
));
}
} else {
if !check_fn_symbol_support(&ctx, fn_name, *arity) {
return Err(format!(
"Function `{fn_name}` with arity {arity} not found in the model."
));
}
}
}
Ok(())
}
}